/*
 * Created on 2005-3-4
 */
package com.hd123.rumba.request;

import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.hd123.rumba.domain.IDomain;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.jsp.LabelHField;
import com.hd123.rumba.organization.IOrganization;
import com.hd123.rumba.user.CPermission;
import com.hd123.rumba.user.IUser;
import com.hd123.rumba.util.ClassifiedHashtable;
import com.hd123.rumba.util.InputValidation;
import com.hd123.rumba.util.InputValidator;
import com.hd123.rumba.util.Iterators;
import com.hd123.rumba.util.StringUtil;

/**
 * @author caili
 */
public class Dictionary extends Hashtable {
  public final static String MISSING = "missing";
  public final static String INVALID = "invalid";
  public final static String INVALIDPERM = "invalid_perm";
  public final static String VALID = "valid";
  public final static String SESSIONMARKER = "tango.sessionValues";
  private HttpSession session;
  private HttpServletRequest request;
  private HttpServletResponse response;
  private Hashtable formValues;
  private Hashtable validFormValues;
  private Hashtable invalidFormValues;
  private Hashtable sessionValues; // reference to

  // session.getAttribute(SESSIONMARKER)

  private void create(HttpSession httpSession) throws IOException {
    this.session = httpSession;
    formValues = new Hashtable();
    validFormValues = new Hashtable();
    invalidFormValues = new Hashtable();
    if (session != null) {
      sessionValues = (Hashtable) session.getAttribute(SESSIONMARKER);
      if (sessionValues == null) {
        sessionValues = new Hashtable();
        session.setAttribute(SESSIONMARKER, sessionValues);
      }
    }
  }

  public Dictionary(HttpSession httpSession) throws IOException {
    super();
    create(httpSession);
  }

  public Dictionary(HttpServletRequest request, HttpServletResponse response) throws IOException {
    super();
    create(request.getSession());
    this.request = request;
    this.response = response;
    Enumeration names = request.getParameterNames();
    if (names != null) {
      while (names.hasMoreElements()) {
        String name = (String) names.nextElement();
        String[] values = request.getParameterValues(name);
        // 这一段不需要了
        // try {
        // name = StringUtil.decodePathInfo(name);
        // for (int i = 0; i < values.length; ++i)
        // values[i] = StringUtil.decodePathInfo(values[i]);
        // } catch (Exception e) {
        // Logger.getLogger(this.getClass()).warn(e.getMessage());
        // }
        if (values.length == 1) {
          formValues.put(name, values[0]);
        } else {
          formValues.put(name, values);
        }
      }
    }
  }

  /**
   * 获取上传的文件, 存放在ActionConstants.TEMPIMPORTDIR指定的目录下. 限制大小size. <br>
   * 填充formValues的内容. 对上传的文件, 其value值是java.io.FILE.
   * 
   * @throws IOException
   * @throws FileTooLargeException
   */
  public void prepareMultipartRequest(int size) throws IOException, FileTooLargeException {
    setMultipartRequestFormValues(new MultipartRequest(request, JspLib.getTempImportDir(request),
        size));
  }

  /**
   * using default 1M
   * 
   * @throws IOException
   * @throws FileTooLargeException
   */
  public void prepareMultipartRequest() throws IOException, FileTooLargeException {
    setMultipartRequestFormValues(new MultipartRequest(request, JspLib.getTempImportDir(request)));
  }

  /**
   * 获取上传的文件, 存放在dir指定的目录下. 限制大小maxSize(byte). <br>
   * 填充formValues的内容. 对上传的文件, 其value值是java.io.FILE.
   * 
   * @param dir
   * @param maxSize
   * @throws IOException
   * @throws FileTooLargeException
   */
  public void prepareMultipartRequest(String dir, int maxSize) throws IOException,
      FileTooLargeException {
    setMultipartRequestFormValues(new MultipartRequest(request, dir, maxSize));
  }

  /**
   * 校验request传入的参数是否合法. request传入的参数在formValues中. 元素为(参数名, 参数值(字符串值)) <br>
   * 如果合法, 转换成相应的类型, 存放在validFormValues中, 元素为(参数名, 参数值(已转换成相应的类型)).
   * 同时标准化formValues中的相应值. <br>
   * 如果不合法, 存放到invalidFormValues(一个Hashtable)中, 形式为(参数名, MISSING或INVALID). <br>
   * 
   * @param name
   * @param rule-
   *          The rule could be a regualre expression, or Integer,
   *          Date(&lt;format&gt;;&lt;format&gt;;...), or
   *          Decimal(fractionDigits).
   * @param required
   * @deprecated 被{@link Dictionary#validateFormValue(String, String, boolean, Object)}替代。
   */
  public Object validateFormValue(String name, String rule, boolean required) {
    String inputValue = (String) getFormValues().get(name);
    if (inputValue != null)
      inputValue.trim();
    Object result = null;
    if (required && ((inputValue == null) || (inputValue.trim().length() == 0))) {
      getInvalidFormValues().put(name + "_" + MISSING, MISSING);
    } else if (inputValue != null && inputValue.trim().length() != 0) {
      InputValidation r = InputValidator.nomalize(inputValue, rule);
      if (r.isValid()) {
        getFormValues().put(name, r.getNomalizedValue());
        getValidFormValues().put(name, r.getTheObject());
        result = r.getTheObject();
      } else {
        getInvalidFormValues().put(name + "_" + INVALID, INVALID);
      }
    }
    return result;
  }

  /**
   * 校验并取得参数取值。<br>
   * 
   * 校验request传入的参数是否合法. request传入的参数在formValues中. 元素为(参数名, 参数值(字符串值)) <br>
   * 如果合法, 转换成相应的类型, 存放在validFormValues中, 元素为(参数名, 参数值(已转换成相应的类型)).
   * 同时标准化formValues中的相应值. <br>
   * 若字段的屏幕状态不是可读写的（参见：{@link LabelHField}），例如当前用户对该字段不可见或只读，将直接返回defValue。<br>
   * 如果不合法, 存放到invalidFormValues(一个Hashtable)中, 形式为(参数名,
   * MISSING或INVALID)。并且将会自动addErrorText。<br>
   * 
   * @param name
   *          指定的request参数名。
   * @param rule
   *          The rule could be a regualre expression, or Integer,
   *          Date(&lt;format&gt;;&lt;format&gt;;...), or
   *          Decimal(fractionDigits).
   * @param required
   *          是否必须参数。
   * @param defValue
   *          默认取值。
   * @param fieldCaption
   *          对应输入字段的显示标题。
   * @return 返回取得值。
   */
  public Object validateFormValue(String name, String rule, boolean required, Object defValue,
      String fieldCaption) {
    String inputValue = (String) getFormValues().get(name);
    if (inputValue != null)
      inputValue.trim();
    boolean readWrite = !"false"
        .equalsIgnoreCase((String) getFormValues().get(name + "_readWrite"));
    if (!readWrite)
      return defValue;

    Object result = null;
    if (required && ((inputValue == null) || (inputValue.trim().length() == 0))) {
      getInvalidFormValues().put(name + "_" + MISSING, MISSING);
      addErrorText("\"" + fieldCaption + "\"必须填写。");
    } else if (inputValue != null && inputValue.trim().length() != 0) {
      InputValidation r = InputValidator.nomalize(inputValue, rule);
      if (r.isValid()) {
        getFormValues().put(name, r.getNomalizedValue());
        getValidFormValues().put(name, r.getTheObject());
        result = r.getTheObject();
      } else {
        getInvalidFormValues().put(name + "_" + INVALID, INVALID);
        addErrorText("\"" + fieldCaption + "\"输入的值不正确。");
      }
    }
    return result;
  }

  /**
   * 取得指定的request参数是否可修改。
   * 
   * @param name
   *          指定的request参数名。
   * @return
   */
  public boolean isWritableFormValue(String name) {
    return "true".equalsIgnoreCase((String) getFormValues().get(name + "_readWrite"));
  }

  /**
   * 检查必添字段当前用户是否拥有足够的字段权限。<br>
   * 如果不合法, 存放到invalidFormValues(一个Hashtable)中, 形式为(字段名,
   * INVALIDPERM)。并且将会自动addErrorText。 <br>
   * 
   * @param fieldName
   *          字段名
   * @param permissionId
   *          对应的字段权限ID。
   * @param fieldValue
   *          字段的初始取值。
   * @param fieldCaption
   *          字段标题
   */
  public void validateRequiredFieldPermission(String fieldName, String permissionId,
      Object fieldValue, String fieldCaption) {
    if (permissionId == null)
      return;
    try {
      if (fieldValue == null) {
        if (!getCurrentUser().hasPermission(permissionId + CPermission.SUFFIX_PERMISSION_EDIT)) {
          getInvalidFormValues().put(fieldName + "_" + INVALIDPERM, INVALIDPERM);
          addErrorText("缺少对于必填属性“" + fieldCaption + "”足够的权限，请与您的系统管理员取得联系。");
        }
      }
    } catch (BusinessException e) {
    }
  }

  public boolean isFormValid() {
    return invalidFormValues.size() == 0;
  }

  /**
   * 返回当前是否权限无效。
   * 
   * @return
   * @see Dictionary#validateRequiredFieldPermission(String, String, Object,
   *      String)
   */
  public boolean isFormValidPerm() {
    return !invalidFormValues.values().contains(INVALIDPERM);
  }

  public String printAll() {
    StringBuffer sb = new StringBuffer();
    sb.append("<pre>");
    sb.append("FormValues<br>");
    String indent = StringUtil.duplicate("&nbsp;", 2);
    sb.append(StringUtil.printAll(getFormValues(), indent, "<br>"));
    sb.append("ValidFormValues<br>");
    sb.append(StringUtil.printAll(getValidFormValues(), indent, "<br>"));
    sb.append("InvalidFormValues<br>");
    sb.append(StringUtil.printAll(getInvalidFormValues(), indent, "<br>"));
    sb.append("Dictionary<br>");
    sb.append(StringUtil.printAll(this, indent, "<br>"));
    sb.append("SessionValues<br>");
    sb.append(StringUtil.printAll(getSessionValues(), indent, "<br>"));
    sb.append("</pre>");
    return sb.toString();
  }

  public Hashtable getFormValues() {
    return formValues;
  }

  public Hashtable getValidFormValues() {
    return validFormValues;
  }

  public Hashtable getInvalidFormValues() {
    return invalidFormValues;
  }

  public HttpServletRequest getRequest() {
    return request;
  }

  public HttpServletResponse getResponse() {
    return response;
  }

  public HttpSession getSession() {
    return session;
  }

  public Hashtable getSessionValues() {
    return sessionValues;
  }

  public static final String CURRENTDOMAIN = "currentDomain";
  public static final String ENTERPRISEDOMAIN = "enterpriseDomain";
  public static final String LOGINUSER = "loginUser";
  public static final String LOGINDOMAIN = "loginDomain";
  public static final String CURRENTUSER = "currentUser";
  public static final String CURRENTORGANIZATION = "currentOrganization";
  public static final String EXTERNALSESSIONS = "externalSessions";

  public IDomain getCurrentDomain() {
    return (IDomain) getSessionValues().get(CURRENTDOMAIN);
  }

  public void setCurrentDomain(IDomain domain) {
    getSessionValues().put(CURRENTDOMAIN, domain);
  }

  public IDomain getLoginDomain() {
    return (IDomain) getSessionValues().get(LOGINDOMAIN);
  }

  public void setLoginDomain(IDomain domain) {
    getSessionValues().put(LOGINDOMAIN, domain);
  }

  public IDomain getEnterpriseDomain() {
    return (IDomain) getSessionValues().get(ENTERPRISEDOMAIN);
  }

  public void setEnterpriseDomain(IDomain enterpriseDomain) {
    getSessionValues().put(ENTERPRISEDOMAIN, enterpriseDomain);
  }

  public IUser getCurrentUser() {
    return (IUser) getSessionValues().get(CURRENTUSER);
  }

  public void setCurrentUser(IUser user) {
    getSessionValues().put(CURRENTUSER, user);
  }

  public IOrganization getCurrentOrganization() {
    return (IOrganization) getSessionValues().get(CURRENTORGANIZATION);
  }

  public void setCurrentOrganization(IOrganization org) {
    if (org != null)
      getSessionValues().put(CURRENTORGANIZATION, org);
  }

  public IUser getLoginUser() {
    return (IUser) getSessionValues().get(LOGINUSER);
  }

  public void setLoginUser(IUser user) {
    getSessionValues().put(LOGINUSER, user);
  }

  public Object putFormValue(Object key, Object value) {
    return getFormValues().put(key, value == null ? "" : value);
  }

  public void removeFormValue(Object key) {
    getFormValues().remove(key);
  }

  public Object getFormValue(Object key) {
    Object value = getFormValues().get(key);
    if (value instanceof String)
      value = ((String) value).trim();
    return value;
  }

  public Object putSessionValue(Object key, Object value) {
    return getSessionValues().put(key, value);
  }

  public Object getSessionValue(Object key) {
    return getSessionValues().get(key);
  }

  public void setWorkingTemplate(String s) {
    put("WorkingTemplate", s);
  }

  public String getWorkingTemplate() {
    return (String) get("WorkingTemplate");
  }

  public Object putCallValue(Object key, Object value) {
    return getFormValues().put("call_" + key, value);
  }

  public Object getCallValue(Object key) {
    return getFormValues().get("call_" + key);
  }

  public String getCallValuesHtml() {
    StringBuffer sb = new StringBuffer();
    sb.append("<!--call values-->");
    Enumeration keys = getFormValues().keys();
    while (keys.hasMoreElements()) {
      String key = (String) keys.nextElement();
      if (key.startsWith("call_")) {
        sb.append("<input type=\"hidden\" name=\"" + key + "\" value=\"" + getFormValue(key)
            + "\" />\n\r");
        sb.append("<input type=\"hidden\" name=\"" + key.substring(5) + "\" value=\""
            + getFormValue(key) + "\" />\n\r");
      }
    }
    sb.append("<!--end of call values-->");
    return sb.toString();
  }

  /**
   * 如果formValues中含有如下的key: prefix1, prefix2, prefix3 <br>
   * 则返回一个iterator of String, 其元素为1, 2, 3 否则返回的iterator.hasNext() == false
   * 
   * @param prefix
   * @return
   */
  public Iterator createFormPrefixedKeysIterator(String prefix) {
    Vector v = new Vector();
    Enumeration keys = formValues.keys();
    while (keys.hasMoreElements()) {
      String key = (String) keys.nextElement();
      if (key.startsWith(prefix))
        v.add(key.substring(prefix.length()));
    }
    return Iterators.createIterator(v);
  }

  /**
   * 如果formValues中含有key(String or String[]), 则返回此key的value值
   * 
   * @param key
   * @return
   */
  public Iterator createFormSelectedValuesIterator(String key) {
    Vector v = new Vector();
    Object s = getFormValue(key);
    if (s != null) {
      if (s instanceof String) {
        v.add(s);
      } else if (s instanceof String[]) {
        String as[] = (String[]) s;
        for (int i = 0; i < as.length; ++i) {
          v.add(as[i]);
        }
      }
    }
    return Iterators.createIterator(v);
  }

  public String getStartNode() {
    return (String) getFormValue("start");
  }

  public void setErrorText(String s) {
    put("_errorText", s);
  }

  public String getErrorText() {
    return (String) get("_errorText");
  }

  public void addErrorText(String s) {
    String e = getErrorText();
    if (e != null)
      setErrorText(e + "<br>" + s);
    else
      setErrorText(s);
  }

  public void setHint(String s) {
    put("_hint", s);
  }

  public String getHint() {
    return (String) get("_hint");
  }

  public void addHint(String s) {
    String h = getHint();
    if (h != null)
      setHint(h + "<br>" + s);
    else
      setHint(s);
  }

  public void setWarning(String s) {
    put("_warning", s);
  }

  public String getWarning() {
    return (String) get("_warning");
  }

  public void addWarning(String s) {
    String h = getWarning();
    if (h != null)
      setWarning(h + "<br>" + s);
    else
      setWarning(s);
  }

  public void setMultipartRequestFormValues(MultipartRequest mr) {
    // 设置form的input name(String)=value(String)
    Enumeration names = mr.getParameterNames();
    if (names != null) {
      while (names.hasMoreElements()) {
        String name = (String) names.nextElement();
        String[] values = mr.getParameter(name);
        // MultipartRequest中已经decode过了.
        // try {
        // name = StringUtil.decodePathInfo(name);
        // for (int i = 0; i < values.length; ++i)
        // values[i] = StringUtil.decodePathInfo(values[i]);
        // } catch (Exception e) {
        // }
        if (values.length == 1) {
          formValues.put(name, values[0]);
        } else {
          formValues.put(name, values);
        }
      }
    }

    // 设置form的input type=file name(String)=value(File)
    Enumeration enumeration = mr.getTypedFileKeys();
    for (int i = 0; enumeration.hasMoreElements(); ++i) {
      String key = (String) enumeration.nextElement();
      File file = (File) mr.getTypedFile(key);
      if (!file.getName().startsWith("unknown.")) {
        formValues.put(key, file);
      }
    }
  }

  /**
   * 将h中的ERROR信息加入到dd的InvalidFormValues和errorText中, WARN信息加入到dd的hint中.
   * 
   * @param prefix
   *          加入到dd的InvalidFormValues时, key的前缀
   * @param h
   */
  public void addInvalidFormValues(String prefix, ClassifiedHashtable h) {
    Iterator i = h.createTypedKeyIterator(ClassifiedHashtable.ERROR);
    while (i != null && i.hasNext()) {
      String key = (String) i.next();
      getInvalidFormValues().put(prefix + key + "_error", h.getMessage(key));
      addErrorText(h.getMessage(key));
    }
    i = h.createTypedKeyIterator(ClassifiedHashtable.WARN);
    while (i != null && i.hasNext()) {
      String key = (String) i.next();
      addHint(h.getMessage(key));
    }
  }
}
